﻿using Furion.Reflection;
using Furion.Reflection.Extensions;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Thor.Core
{
    public class TransactionalAop: AspectDispatchProxy, IGlobalDispatchProxy
    {
        /// <summary>
        /// 当前服务实例
        /// </summary>
        public object Target { get; set; }

        /// <summary>
        /// 服务提供器，可以用来解析服务，如：Services.GetService()
        /// </summary>
        public IServiceProvider Services { get; set; }

        /// <summary>
        /// 拦截方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public override object Invoke(MethodInfo method, object[] args)
        {
            object result;

            var attribute = method.GetActualCustomAttributes<TransactionalAttribute>(Target).FirstOrDefault();
            if (attribute == null)
            {
                result = method.Invoke(Target, args);
            }
            else
            {
                var unitOfWork = Services.GetService<IUnitOfWork>();
                try
                {
                    unitOfWork.BeginTran(attribute.ConfigId, attribute.IsolationLevel);

                    result = method.Invoke(Target, args);

                    unitOfWork.CommitTran();
                }
                catch
                {
                    unitOfWork.RollbackTran();
                    throw;
                }
            }
            return result;
        }

        // 异步无返回值
        public override async Task InvokeAsync(MethodInfo method, object[] args)
        {
            var attribute = method.GetActualCustomAttributes<TransactionalAttribute>(Target).FirstOrDefault();

            if(attribute == null)
            {
                await (method.Invoke(Target, args) as Task);
            }
            else
            {
                var unitOfWork = Services.GetService<IUnitOfWork>();

                try
                {
                    unitOfWork.BeginTran(attribute.ConfigId, attribute.IsolationLevel);

                    await (method.Invoke(Target, args) as Task);

                    unitOfWork.CommitTran();
                }
                catch
                {
                    unitOfWork.RollbackTran();
                    throw;
                }
            }
        }

        // 异步带返回值
        public override async Task<T> InvokeAsyncT<T>(MethodInfo method, object[] args)
        {
            T result;

            var attribute = method.GetActualCustomAttributes<TransactionalAttribute>(Target).FirstOrDefault();

            if (attribute == null)
            {
                result = await (method.Invoke(Target, args) as Task<T>);
            }
            else
            {
                var unitOfWork = Services.GetService<IUnitOfWork>();
                try
                {
                    unitOfWork.BeginTran(attribute.ConfigId, attribute.IsolationLevel);

                    result = await (method.Invoke(Target, args) as Task<T>);

                    unitOfWork.CommitTran();
                }
                catch
                {
                    unitOfWork.RollbackTran();
                    throw;
                }
            }

            return result;
        }
    }
}
